<%# The license inside this block applies to this file.
	# Copyright 2020 Google Inc.
	# Licensed under the Apache License, Version 2.0 (the "License");
	# you may not use this file except in compliance with the License.
	# You may obtain a copy of the License at
	#
	#     http://www.apache.org/licenses/LICENSE-2.0
	#
	# Unless required by applicable law or agreed to in writing, software
	# distributed under the License is distributed on an "AS IS" BASIS,
	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	# See the License for the specific language governing permissions and
	# limitations under the License.
-%>
// Fields in "backends" that are not allowed for non-managed backend services
// (loadBalancingScheme) - the API returns an error if they are set at all
// in the request.
var backendServiceOnlyManagedFieldNames = []string{
	"capacity_scaler",
	"max_connections",
	"max_connections_per_instance",
	"max_connections_per_endpoint",
	"max_rate",
	"max_rate_per_instance",
	"max_rate_per_endpoint",
	"max_utilization",
}

// validateManagedBackendServiceBackends ensures capacity_scaler is set for each backend in a managed
// backend service. To prevent a permadiff, we decided to override the API behavior and require the
//// capacity_scaler value in this case.
//
// The API:
// - requires the sum of the backends' capacity_scalers be > 0
// - defaults to 1 if capacity_scaler is omitted from the request
//
// However, the schema.Set Hash function defaults to 0 if not given, which we chose because it's the default
// float and because non-managed backends can't have the value set, so there will be a permadiff for a
// situational non-zero default returned from the API. We can't diff suppress or customdiff a
// field inside a set object in ResourceDiff, since the value also determines the hash for that set object.
func validateManagedBackendServiceBackends(backends []interface{}, d *schema.ResourceDiff) error {
	sum := 0.0

	for _, b := range backends {
		if b == nil {
			continue
		}
		backend := b.(map[string]interface{})
		if v, ok := backend["capacity_scaler"]; ok && v != nil {
			sum += v.(float64)
		} else {
			return fmt.Errorf("capacity_scaler is required for each backend in managed backend service")
		}
	}
	if sum == 0.0 {
		return fmt.Errorf("managed backend service must have at least one non-zero capacity_scaler for backends")
	}
	return nil
}

// If INTERNAL or EXTERNAL, make sure the user did not provide values for any of the fields that cannot be sent.
// We ignore these values regardless when sent to the API, but this adds plan-time validation if a
// user sets the value to non-zero. We can't validate for empty but set because
// of how the SDK handles set objects (on any read, nil fields will get set to empty values)
func validateNonManagedBackendServiceBackends(backends []interface{}, d *schema.ResourceDiff) error {
	for _, b := range backends {
		if b == nil {
			continue
		}
		backend := b.(map[string]interface{})
		for _, fn := range backendServiceOnlyManagedFieldNames {
			if v, ok := backend[fn]; ok && !isEmptyValue(reflect.ValueOf(v)) {
				return fmt.Errorf("%q cannot be set for non-managed backend service, found value %v", fn, v)
			}
		}
	}
	return nil
}

func customDiffRegionBackendService(_ context.Context, d *schema.ResourceDiff, meta interface{}) error {
	v, ok := d.GetOk("backend")
	if !ok {
		return nil
	}
	if v == nil {
		return nil
	}

	backends := v.(*schema.Set).List()
	if len(backends) == 0 {
		return nil
	}

	switch d.Get("load_balancing_scheme").(string) {
	case "INTERNAL", "EXTERNAL":
		return validateNonManagedBackendServiceBackends(backends, d)
	default:
		return validateManagedBackendServiceBackends(backends, d)
	}
}
